package com.smart.community.commons.exception;

import com.smart.community.commons.result.Result;
import com.smart.community.commons.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 统一处理系统中抛出的各种异常
 * @author Wu.Liang
 * @since 2024-12-19
 * @version 1.0.0
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
	
	/**
	 * 处理系统异常
	 * 根据《业务异常日志处理规范.md》权威标准：
	 * - 系统异常：记录异常消息和完整堆栈信息
	 * 
	 * @param e 系统异常
	 * @return 统一响应结果
	 */
	@ExceptionHandler(SystemException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public Result<Void> handleSystemException(SystemException e) {
		// 系统异常：记录异常消息和完整堆栈
		log.error("系统异常: {}", e.getMessage(), e);
		return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), e.getMessage());
	}
    
    /**
     * 处理业务异常
     * 根据《业务异常日志处理规范.md》权威标准：
     * - 业务异常：只记录异常消息，不打印堆栈信息
     * 
     * @param e 业务异常
     * @return 统一响应结果
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleBusinessException(BusinessException e) {
        // 业务异常：只记录异常消息，不打印堆栈
        log.warn("业务异常: {}", e.getMessage());
        return Result.fail(e.getCode(), e.getMessage());
    }
    
    /**
     * 处理参数类型转换异常
     * 
     * @param e 参数类型转换异常
     * @return 统一响应结果
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        String message = String.format("参数类型转换失败: 参数 '%s' 的值 '%s' 无法转换为 %s 类型", e.getName(), e.getValue(), e.getRequiredType().getSimpleName());
        log.error("参数类型转换异常: {}", message, e);
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), message);
    }
    
    /**
     * 处理参数校验异常（@Valid）
     * 
     * @param e 参数校验异常
     * @return 统一响应结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        log.error("参数校验异常: {}", message, e);
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), message);
    }
    
    /**
     * 处理参数绑定异常
     * 
     * @param e 参数绑定异常
     * @return 统一响应结果
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleBindException(BindException e) {
        String message = e.getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        log.error("参数绑定异常: {}", message, e);
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), message);
    }
    
    /**
     * 处理约束违反异常
     * 
     * @param e 约束违反异常
     * @return 统一响应结果
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleConstraintViolationException(ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
        log.error("约束违反异常: {}", message, e);
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), message);
    }
    
    /**
     * 处理权限异常
     * 根据《业务异常日志处理规范.md》权威标准：
     * - 业务异常：只记录异常消息，不打印堆栈信息
     * 
     * @param e 权限异常
     * @return 统一响应结果
     */
    @ExceptionHandler(PermissionException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result<Void> handlePermissionException(PermissionException e) {
        // 业务异常：只记录异常消息，不打印堆栈
        log.warn("权限异常: {}", e.getMessage());
        return Result.fail(ResultCode.PERMISSION_DENIED.getCode(), e.getMessage());
    }
    
    	/**
	 * 处理认证异常
	 * 根据《业务异常日志处理规范.md》权威标准：
	 * - 业务异常：只记录异常消息，不打印堆栈信息
	 * 
	 * @param e 认证异常
	 * @return 统一响应结果
	 */
	@ExceptionHandler(AuthenticationException.class)
	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	public Result<Void> handleAuthenticationException(AuthenticationException e) {
		// 业务异常：只记录异常消息，不打印堆栈
		log.warn("认证异常: {}", e.getMessage());
		return Result.fail(ResultCode.UNAUTHORIZED.getCode(), e.getMessage());
	}
    
    /**
     * 模块业务异常
     * 根据《业务异常日志处理规范.md》权威标准：
     * - 业务异常：只记录异常消息，不打印堆栈信息
     * 
     * @param e 模块业务异常
     * @return 统一响应结果
     */
    @ExceptionHandler(ModuleBusinessException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result<Void> handleModuleBusinessException(ModuleBusinessException e) {
        // 业务异常：只记录异常消息，不打印堆栈
    	log.warn("模块业务异常: {}", e.getMessage());
    	return Result.fail(ResultCode.SERVICE_UNAVAILABLE.getCode(), e.getMessage());
    }
    
    /**
     * 处理数据不存在异常
     * 根据《业务异常日志处理规范.md》权威标准：
     * - 业务异常：只记录异常消息，不打印堆栈信息
     * 
     * @param e 数据不存在异常
     * @return 统一响应结果
     */
    @ExceptionHandler(DataNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result<Void> handleDataNotFoundException(DataNotFoundException e) {
        // 业务异常：只记录异常消息，不打印堆栈
        log.warn("数据不存在异常: {}", e.getMessage());
        return Result.fail(ResultCode.DATA_NOT_FOUND.getCode(), e.getMessage());
    }
    
    /**
     * 处理数据已存在异常
     * 根据《业务异常日志处理规范.md》权威标准：
     * - 业务异常：只记录异常消息，不打印堆栈信息
     * 
     * @param e 数据已存在异常
     * @return 统一响应结果
     */
    @ExceptionHandler(DataAlreadyExistsException.class)
    @ResponseStatus(HttpStatus.CONFLICT)
    public Result<Void> handleDataAlreadyExistsException(DataAlreadyExistsException e) {
        // 业务异常：只记录异常消息，不打印堆栈
        log.warn("数据已存在异常: {}", e.getMessage());
        return Result.fail(ResultCode.DATA_ALREADY_EXISTS.getCode(), e.getMessage());
    }
    
    /**
     * 处理文件上传大小超限异常
     * 
     * @param e 文件上传大小超限异常
     * @return 统一响应结果
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        log.warn("文件上传大小超限: {}", e.getMessage());
        return Result.fail(ResultCode.VALIDATION_FAILED.getCode(), 
            "文件大小不能超过10MB，请选择较小的文件");
    }
    
    /**
     * 处理文件上传异常
     * 
     * @param e 文件上传异常
     * @return 统一响应结果
     */
    @ExceptionHandler(MultipartException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleMultipartException(MultipartException e) {
        log.error("文件上传异常: {}", e.getMessage(), e);
        return Result.fail(ResultCode.FILE_UPLOAD_ERROR.getCode(), 
            "文件上传失败，请检查文件格式和大小");
    }
    
    /**
     * 处理系统异常
     * 
     * @param e 系统异常
     * @return 统一响应结果
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常: {}", e.getMessage(), e);
        return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统内部错误，请联系管理员");
    }
}
